#include "share/std_err.h"
#include "share/unios.h"
#include "ad9695.h"

/**
 * AD9595 的寄存器为 24 位，高位在前
 * bit[23:23]: R(1)/W(0) 标志
 * bit[22:8 ]: 15 位寄存器地址
 * bit[7 :0 ]: 8 位寄存器值
 */
 
static std_err_t _regw(unidrv_ad9695_t *dev, uint16_t regaddr, uint8_t regval) {
	uint8_t tx[3], rx[3];
    // 注意：big-endian(大端在前)
    tx[0] = (regaddr >> 8 ) & 0x7F;
    tx[1] = (regaddr      ) & 0xFF;
    tx[2] = regval;
    
    dev->nss(0); //{{{
    std_err_t err = mcu_spi_trx(dev->spi, tx, rx, 3, NULL);
    dev->nss(1); //}}}
    return err;
}

static uint8_t _regr(unidrv_ad9695_t *dev, uint16_t regaddr) {
	uint8_t tx[3], rx[3];
    // 注意：big-endian(大端在前)
    tx[0] = ((regaddr >> 8) & 0xFF) | 0x80; // R(1)/W(0) 标志设置为 1 表示读寄存器
    tx[1] = regaddr & 0xFF;
    tx[2] = 0xFF;
    
    dev->nss(0); //{{{
    mcu_spi_trx(dev->spi, tx, rx, 3, NULL);
    dev->nss(1); //}}}
    return rx[2];
}

static std_err_t _spi_reg_write(unidrv_ad9695_t *dev, uint32_t regval) {
	uint8_t tx[3], rx[3];
    // 注意：只发低 24 位，并且要 big-endian(大端在前)
    tx[0] = (regval >> 16) & 0x7F;
    tx[1] = (regval >> 8 ) & 0xFF;
    tx[2] = (regval      ) & 0xFF;
    
    dev->nss(0); //{{{
    std_err_t err = mcu_spi_trx(dev->spi, tx, rx, 3, NULL);
    dev->nss(1); //}}}
    return err;
}

std_err_t unidrv_ad9695_init(unidrv_ad9695_t *dev, uint32_t *regs) {
    if(!dev || !dev->spi || !dev->nss || !dev->pdwn_out || !dev->fd_a_in || !dev->fd_b_in || !regs) return STD_ERR_INVALID_ARG;
    std_err_t err;
    
    // PDWN 拉高 -> 拉低，实现对 AD9695 的复位控制
    dev->pdwn_out(1); unios_us_delay(1000); dev->pdwn_out(0); unios_us_delay(10000);    
    _regw(dev, 0x000, 0x81); unios_us_delay(10000); // SOFTREST, MSB, 地址递增
    
    // 检查芯片类型
    if(_regr(dev, 0x003) != 0x03) {
        return STD_ERR_INVALID_ID;
    }
    
    // 检查芯片PID
    uint16_t pid   = _regr(dev, 0x004);
    pid = (pid<<8) | _regr(dev, 0x005);
    if(pid != 0xDE00) return STD_ERR_INVALID_ID;
    
	for(int i=0; regs[i] != 0xFFFFFFFF; i++) {
        _spi_reg_write(dev, regs[i]);
		unios_us_delay(10000);
	}
	unios_us_delay(10000);

    // AD9695 对应的 JESD 接口初始化
    if(dev->jesd_init) {
        err = dev->jesd_init();
        if(err) return err;
    }
    
	return STD_ERR_OK;
}
